package com.demo;


import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * 映射实现类
 */
public class PVConvertMappingObject implements ConvertMappingObject {
    @Override
    public <U, T> T convert(U origin, T dest) {

        Class<T> originClazz = (Class<T>) origin.getClass();
        // 获取原始对象所有的方法
        Method[] originMethods = originClazz.getDeclaredMethods();

        // 原始对象中get方法
        List<Method> originMethodList = Arrays.stream(originMethods)
                .filter(method -> method.getName().startsWith("get")).collect(Collectors.toList());

        Class<T> destClazz = (Class<T>) dest.getClass();
        // 获取最终对象所有的方法
        Method[] destMethods = destClazz.getDeclaredMethods();


        Arrays.stream(destMethods)
                .filter(method -> method.getName().startsWith("set"))
                .forEach(method -> {
                    // 获取方法上的ConvertMapping注解
                    ConvertMapping convertMapping = method.getAnnotation(ConvertMapping.class);
                    if (null != convertMapping) {
                        // 获取方法参数
                        Class<?> paramClazz = method.getParameterTypes()[0];
                        // 获取注解的值
                        String value = convertMapping.value();
                        // 原始类的get方法
                        String getValue = "get" + value.substring(0, 1).toUpperCase() + value.substring(1);

                        AtomicBoolean isMatch = new AtomicBoolean(false);

                        originMethodList.forEach(method1 -> {
                            if (getValue.equals(method1.getName())) {
                                isMatch.set(true);
                                try {
                                    Object field = method1.invoke(origin);

                                    if (null != field) {
                                        // 原始对象get方法返回对象的类型
                                        String originFieldTypeName = field.getClass().getTypeName();
                                        // 目标对象set方法返接收象的类型
                                        String destFieldTypeName = paramClazz.getTypeName();

                                        // 如果类型相同直接设置
                                        if (originFieldTypeName.equals(destFieldTypeName)) {
                                            method.invoke(dest, field);
                                        } else if ("java.lang.String".equals(originFieldTypeName) && "java.lang.Integer".equals(destFieldTypeName)) {
                                            // 原始对象String, 目标对象Integer
                                            method.invoke(dest, Integer.valueOf((String) field));
                                        } else if ("java.lang.Number".equals(field.getClass().getSuperclass().getTypeName()) && "java.lang.String".equals(destFieldTypeName)) {
                                            // 原始对象是基本数据类型, 目标对象是String
                                            method.invoke(dest, String.valueOf(field));
                                        } else if ("java.util.Date".equals(originFieldTypeName) && "java.lang.String".equals(destFieldTypeName)) {
                                            // 原始对象为Date类型, 目标对象是String类型
                                            method.invoke(dest, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(field));
                                        } else {
                                            // todo 此条件用于捕获没想到的情况
                                            method.invoke(dest, field);
                                        }
                                    }

                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        });

                        if (!isMatch.get()) {
                            try {
                                throw new Exception("注解值异常: 请检查 " + method.getName() + "() 方法上ConvertMapping注解的value是否正确!");
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }

                    }

                });



        return dest;
    }
}
